//*****************************************************************
// OperatorThread.cpp
//
//  Created on: Jan 21, 2012
//      Author: Christopher Wood
//              Robert Livosi
//
//  $Id: OperatorThread.cpp 30 2012-01-29 21:29:24Z caw4567 $
//*****************************************************************

#include "OperatorThread.h"
#include "Controller.h"
#include "Project2.h"

/**
 * The (friendly) user input thread function.
 *
 * @param arg - pointer to the host PIDControlThread object.
 */
void* userInputThread(void* arg);

/**
 * Default constructor that sets the transform and I/O threads.
 *
 * @param controller - the desired transform thread to control.
 * @param ioGroup - the I/O group that is managed.
 */
OperatorThread::OperatorThread(Controller* controller, IOThreadGroup* ioGroup)
{
	this->controller = controller;
	this->ioGroup = ioGroup;
}

/**
 * Default destructor.
 */
OperatorThread::~OperatorThread()
{
}

/**
 * The (friendly) user input thread function.
 *
 * @param arg - pointer to the host PIDControlThread object.
 */
void* userInputThread(void* arg)
{
	OperatorThread* theOperator = (OperatorThread*)arg;
	string controlInput;
	string algorithmInput;
	int continueFlag = 1;

	// Loop and collect user input to modify the PID controller on the fly.
	while (continueFlag)
	{
		// Read in the controller parameters
		string controlParam = (theOperator->getController())->getParamString();
		cout << controlParam.c_str();
		getline(cin, controlInput);
		theOperator->getController()->setParams(controlInput);

		// Read in the algorithm parameters
		string algParam = ((theOperator->getController())->getAlgorithm())->getParamString();
		cout << algParam.c_str();
		int numParams = ((theOperator->getController())->getAlgorithm())->getParamLength();
		vector<string> algParams;
		for (int i = 0; i < numParams; i++)
		{
			getline(cin, algorithmInput);
			algParams.push_back(algorithmInput);
		}
		theOperator->getController()->getAlgorithm()->setParams(algParams);

		// Termination flag
		cout << "0 to terminate, 1 to continue: ";
		cin >> continueFlag;

		// Flush all streams
		cin.clear();
		cout.clear();
		fflush(stdin);
		fflush(stdout);
		cin.ignore();
	}

	// Terminate all threads for cleanup and then exit
	(theOperator->getController())->setThreadState(false);
	(theOperator->getController())->release();
	(theOperator->getIOThreadGroup())->setInputThreadState(false);
	(theOperator->getIOThreadGroup())->releaseInputThread();
	(theOperator->getIOThreadGroup())->setOutputThreadState(false);
	(theOperator->getIOThreadGroup())->releaseOutputThread();

	// We're complete now.
	theOperator->setComplete(true);
	pthread_exit(NULL);
}

/**
 * Start the thread.
 */
void OperatorThread::run()
{
	pthread_create(&threadID, NULL, userInputThread, this);
}

/**
 * Retrieve the transform object being controlled by this thread.
 *
 * @return a pointer to the transform thread object
 */
Controller* OperatorThread::getController()
{
	return controller;
}

/**
 * Retrieve a pointer to the IOThreadGroup object being controlled by this thread.
 *
 * @param a pointer to the IOThreadGroup object.
 */
IOThreadGroup* OperatorThread::getIOThreadGroup()
{
	return ioGroup;
}

/**
 * Determine if this thread is done controlling the others.
 *
 * @return true if done, false otherwise.
 */
bool OperatorThread::isComplete()
{
	return controlComplete;
}

/**
 * Set the control completion status.
 *
 * @param b - new boolean value.
 */
void OperatorThread::setComplete(bool b)
{
	controlComplete = b;
}
